﻿using CHANGEOBJECT;
using ECAN;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using TestLog;
using ZLGCAN;

namespace ZLGUDS
{
    using ZUDS_HANDLE = UInt32;
    using PARAM_TYPE = Byte;
    using UDS_STATUS = Byte;
    using TP_TYPE = UInt32;
    using RESPONSE_TYPE = Byte;

    #region CAN连接读取类

    public static class CanCommunication
    {
        /// <summary>
        /// 增加的帧头
        /// </summary>
        public const string strFrameHeader = "31 01 FB 35";

        /// <summary>
        /// true=周立功CAN盒；false=广成CAN盒
        /// </summary>
        public static bool bZlgCan = true;

        /// <summary>
        /// 是否发送下一帧数据
        /// </summary>
        public static bool bSendNextFrame = false;

        /// <summary>
        /// 是否启动CAN
        /// </summary>
        public static bool[] bCanStatus = new bool[9];

        public static ZUDS.ZUDS_RESPONSE[] zResp = new ZUDS.ZUDS_RESPONSE[9];
        public static byte[] bRecvData;

        public static ZUDS.OnUDSTransmit Callback;

        static TestLogFile tLog = new TestLogFile("");

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public static void ConnectCan(int iPassageway, string strDevType, string strBaudrate)
        {
            string strDevIndex = "0";
            string strAccCode = "000000";
            string strAccMask = "FFFFFF";
            string strTime0 = "0";
            string strTime1 = "1c";

            IntPtr IP = new IntPtr(iPassageway);

            ZUDS.ZUDS_Release(ZUDS.zudsHandle[iPassageway]);
            ZUDS.zudsHandle[iPassageway] = ZUDS.ZUDS_Init(ZUDS.DoCan);

            
            Callback = ZUDS.OnUDSTransmitFunc;
            ZUDS.ZUDS_SetTransmitHandler(ZUDS.zudsHandle[iPassageway], IP, Callback);

            for (int i = 0; i < 3; i++)
            {
                switch (strDevType)
                {
                    case "USBCAN-I":
                        bZlgCan = true;
                        Method.nDeviceType[iPassageway] = 3;
                        break;
                    case "USBCAN-II":
                        Method.nDeviceType[iPassageway] = 4;
                        break;
                    case "USBCAN-4E-U":
                        Method.nDeviceType[iPassageway] = 31;
                        break;
                    case "USBCAN-2E-U":
                        Method.nDeviceType[iPassageway] = 21;
                        break;
                    case "USBCAN-200-U":
                        Method.nDeviceType[iPassageway] = 41;
                        Method.canfdDevice = true;
                        Method.usbCanfd = true;
                        break;
                    case "GC-USBCAN-I":
                        bZlgCan = false;
                        Method.nDeviceType[iPassageway] = 88;
                        ECANDLL.strCanDevType = strDevType;
                        break;
                    case "GC-USBCAN-II":
                        bZlgCan = false;
                        Method.nDeviceType[iPassageway] = 88;
                        ECANDLL.strCanDevType = strDevType;
                        break;
                }

                if (bZlgCan)
                {
                    ZCAN_CHANNEL_INIT_CONFIG iniConfig = new ZCAN_CHANNEL_INIT_CONFIG();
                    if (Method.m_bOpen[iPassageway] == 1)
                    {
                        Method.CloseCAN(iPassageway);
                        Method.m_bOpen[iPassageway] = 0;
                    }
                    else
                    {

                        switch (strDevIndex)
                        {
                            case "0":
                                Method.nDeviceIndex[iPassageway] = 0;
                                break;
                            case "1":
                                Method.nDeviceIndex[iPassageway] = 1;
                                break;
                        }
                        switch (iPassageway)
                        {
                            case 1:
                                Method.nCANInd = 0;
                                break;
                            case 2:
                                Method.nCANInd = 1;
                                break;
                            case 3:
                                Method.nCANInd = 2;
                                break;
                            case 4:
                                Method.nCANInd = 3;
                                break;
                        }
                        Method.Baudrate = (uint)(Convert.ToInt32(strBaudrate) * 1000);
                        iniConfig.can.acc_code = Convert.ToUInt32("0x" + strAccCode, 16);
                        iniConfig.can.acc_mask = Convert.ToUInt32("0x" + strAccMask, 16);
                        iniConfig.can.timing0 = Convert.ToByte("0x" + strTime0, 16);
                        iniConfig.can.timing1 = Convert.ToByte("0x" + strTime1, 16);
                        iniConfig.can.filter = 0;
                        iniConfig.can.mode = 0;
                        if (!Method.usbCanfd)
                        {
                            iniConfig.can_type = Define.TYPE_CAN;
                        }
                        else
                        {
                            iniConfig.can_type = Define.TYPE_CANFD;
                        }

                        if (!Method.OpenCAN(iPassageway))
                        {
                            Method.CloseCAN(iPassageway);
                            Method.m_bOpen[iPassageway] = 0;
                            Console.WriteLine("打开失败");
                        }
                        else
                        {
                            Thread.Sleep(100);
                            Method.iConfig = iniConfig;
                            if (!Method.InitCAN(iPassageway, iniConfig))
                            {
                                Method.CloseCAN(iPassageway);
                                Method.m_bOpen[iPassageway] = 0;
                                Console.WriteLine("初始化失败");
                            }
                            Method.m_bOpen[iPassageway] = 1;
                        }
                    }
                }
                else
                {
                    ECANDLL.strCanBand = strBaudrate;
                    ECANDLL.strCanAccCode = strAccCode;
                    ECANDLL.strCanAccMask = strAccMask;
                    ECANDLL.iCanFilterIndex = (Byte)0;

                    if (ECANDLL.OpenCan(iPassageway) != 0)
                    {
                        ECANDLL.GcCloseCan(iPassageway);
                        Method.m_bOpen[iPassageway] = 0;
                        Console.WriteLine("打开失败");
                    }
                    Method.m_bOpen[iPassageway] = 1;
                }
                if (Method.m_bOpen[iPassageway] == 1)
                {
                    break;
                }

            }
        }

        public static void CloseCan(int iChannel)
        {
            if (bZlgCan)
            {
                Method.CloseCAN(iChannel);
            }
            else
            {
                ECANDLL.GcCloseCan(iChannel);
            }
            Method.m_bOpen[iChannel] = 0;
        }

        /// <summary>
        /// 启动CAN进行收发,并启动接收线程
        /// </summary>
        public static void StartCan(int iPassageway)
        {
            string strData = "";

            for (int j = 0; j < 5; j++)
            {
                if (bZlgCan)
                {
                    if (Method.m_bOpen[iPassageway] != 0)
                    {
                        if (Method.StartCAN(iPassageway))
                        {
                            bCanStatus[iPassageway] = true;
                        }
                        else
                        {
                            Method.ResetCAN(iPassageway);
                        }
                    }
                }
                else
                {
                    if (ECANDLL.GcStartCan(iPassageway) != -1)
                    {
                        bCanStatus[iPassageway] = true;
                    }
                }
                if (bCanStatus[iPassageway])
                {
                    MessageBox.Show("通道" + iPassageway.ToString() + "CAN启动成功！", "成功",
                                    MessageBoxButtons.OK, MessageBoxIcon.None);
                    break;
                }

            }
            if (bCanStatus[iPassageway])
            {
                var task1 = Task.Factory.StartNew(() =>
                {
                    while (bCanStatus[iPassageway])
                    {
                        ZUDS.ZUDS_FRAME zuds_frame = new ZUDS.ZUDS_FRAME();
                        zuds_frame.data = new byte[64];

                        if (bZlgCan)
                        {
                            ZCAN_Receive_Data canData = Method.RecvFunc(iPassageway);
                            ZUDS.ZCANToUDSFrame(ref zuds_frame, canData.frame.can_id, canData.frame.can_dlc, canData.frame.data);
                            //if (canData.frame.data != null)
                            if (canData.frame.can_id != 0)
                            {
                                strData = string.Format("接收:ID[0x{0:X6}], DATA[{1}]", canData.frame.can_id, Change.BytesToHexString(canData.frame.data, 0, canData.frame.can_dlc, " "));
                                tLog.WriteLog(strData, "data");
                            }
                        }
                        else
                        {
                            CAN_OBJ canData = ECANDLL.GcReadRecv(iPassageway);
                            ZUDS.ZCANToUDSFrame(ref zuds_frame, canData.ID, canData.DataLen, canData.data);
                            //if (canData.data != null)
                            if (canData.ID != 0)
                            {
                                strData = string.Format("接收:ID[0x{0:X6}], DATA[{1}]", canData.ID, Change.BytesToHexString(canData.data, 0, canData.DataLen, " "));
                                tLog.WriteLog(strData, "data");
                            }
                        }
                        ZUDS.ZUDS_OnReceive(ZUDS.zudsHandle[iPassageway], ref zuds_frame);
                    }
                });
            }
        }
    }

    #endregion


    public class ZUDS
    {
        static TestLogFile tLog = new TestLogFile("");

        public static ZUDS_HANDLE[] zudsHandle = new ZUDS_HANDLE[9];

        public const Int32 ZUDS_INVALID_HANDLE = -1;

        public const UInt32 DoCan = 0;

        public static bool use_canfd = false;

        public const byte ZUDS_SI_DiagnosticSessionControl = 0x10;
        public const byte ZUDS_SI_ECUReset = 0x11;
        public const byte ZUDS_SI_ClearDiagnosticInformation = 0x14;
        public const byte ZUDS_SI_ReadDTCInformation = 0x19;
        public const byte ZUDS_SI_ReadDataByIdentifier = 0x22;
        public const byte ZUDS_SI_ReadMemoryByAddress = 0x23;
        public const byte ZUDS_SI_ReadScalingDataByIdentifier = 0x24;
        public const byte ZUDS_SI_SecurityAccess = 0x27;
        public const byte ZUDS_SI_CommunicationControl = 0x28;
        public const byte ZUDS_SI_ReadDataByPeriodicIdentifier = 0x2A;
        public const byte ZUDS_SI_DynamicallyDefineDataIdentifier = 0x2C;
        public const byte ZUDS_SI_WriteDataByIdentifier = 0x2E;
        public const byte ZUDS_SI_InputOutputControlByIdentifier = 0x2F;
        public const byte ZUDS_SI_RoutineControl = 0x31;
        public const byte ZUDS_SI_RequestDownload = 0x34;
        public const byte ZUDS_SI_RequestUpload = 0x35;
        public const byte ZUDS_SI_TransferData = 0x36;
        public const byte ZUDS_SI_RequestTransferExit = 0x37;
        public const byte ZUDS_SI_WriteMemoryByAddress = 0x3D;
        public const byte ZUDS_SI_TesterPresent = 0x3E;
        public const byte ZUDS_SI_AccessTimingParameter = 0x83;
        public const byte ZUDS_SI_SecuredDataTransmission = 0x84;
        public const byte ZUDS_SI_ControlDTCSetting = 0x85;
        public const byte ZUDS_SI_ResponseOnEvent = 0x86;
        public const byte ZUDS_SI_LinkControl = 0x87;

        #region 错误码
        /// <summary>
        /// 没错误
        /// </summary>
        public const byte ZUDS_ERROR_OK = 0;

        /// <summary>
        /// 响应超时
        /// </summary>
        public const byte ZUDS_ERROR_TIMEOUT = 1;

        /// <summary>
        /// 发送数据失败
        /// </summary>
        public const byte ZUDS_ERROR_TRANSPORT = 2;

        /// <summary>
        /// 取消请求
        /// </summary>
        public const byte ZUDS_ERROR_CANCEL = 3;

        /// <summary>
        /// 抑制响应
        /// </summary>
        public const byte ZUDS_ERROR_SUPPRESS_RESPONSE = 4;

        public const byte ZUDS_ERROR_OTHTER = 100;

        #endregion

        /// <summary>
        /// 积极响应
        /// </summary>
        public const byte RT_POSITIVE = 1;

        /// <summary>
        /// 消极响应
        /// </summary>
        public const byte RT_NEGATIVE = 0;


        #region param
        /// <summary>
        /// ZUDS_SESSION_PARAM
        /// </summary>
        public const byte PARAM_TYPE_SESSION = 0;

        /// <summary>
        /// ZUDS_ISO15765_PARAM
        /// </summary>
        public const byte PARAM_TYPE_ISO15765 = 1;

        public const byte PARAM_TYPE_TRANSPORT = 2;
        #endregion

        #region 传输协议版本

        /// <summary>
        /// ISO15765-2(2004版本)
        /// </summary>
        public const byte VERSION_0 = 0;

        /// <summary>
        ///  ISO15765-2(2016版本)
        /// </summary>
        public const byte VERSION_1 = 1;
        #endregion

        public const byte TRANSPORT_OK = 0;
        public const byte TRANSPORT_ERROR = 1;



        #region 结构体

        /// <summary>
        /// 请求
        /// </summary>
        [StructLayout(layoutKind: LayoutKind.Sequential, Pack = 4)]
        public struct ZUDS_REQUEST
        {
            /// <summary>
            /// 请求地址
            /// </summary>
            public UInt32 src_addr;

            /// <summary>
            /// 响应地址
            /// </summary>
            public UInt32 dst_addr;

            /// <summary>
            /// 1:抑制响应
            /// </summary>
            public byte suppress_response;

            /// <summary>
            /// 请求服务id
            /// </summary>
            public byte sid;

            /// <summary>
            /// // 参数数组
            /// </summary>
            public IntPtr param;

            /// <summary>
            /// 参数数组的长度
            /// </summary>
            public UInt32 param_len;

            /// <summary>
            /// 保留
            /// </summary>
            public UInt32 reserved;
        }

        /// <summary>
        /// 应答
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct ZUDS_RESPONSE
        {
            /// <summary>
            /// 错误码
            /// </summary>
            public byte status;

            /// <summary>
            /// RESPONSE_TYPE
            ///RT_POSITIVE, RT_NEGATIVE
            /// </summary>
            public byte type;


            /// <summary>
            /// 响应联合体
            /// </summary>
            public UnionNP un;

            public UInt32 reserved; //保留 
        }

        /// <summary>
        /// 积极响应与消极响应联合体
        /// </summary>
        [StructLayout(LayoutKind.Explicit)]
        public struct UnionNP
        {
            [FieldOffset(0)]
            public Positive positive;

            [FieldOffset(0)]
            public Negative negative;
        }

        /// <summary>
        /// 积极应答
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct Positive
        {
            /// <summary>
            /// 响应服务id
            /// </summary>
            public byte sid;

            /// <summary>
            /// 参数数组, 不用释放
            /// </summary>
            public IntPtr param;

            /// <summary>
            /// 参数数组的长度
            /// </summary>
            public UInt32 param_len;
        }

        /// <summary>
        /// 消极应答
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct Negative
        {
            /// <summary>
            /// 0x7F
            /// </summary>
            public byte neg_code;

            /// <summary>
            /// 请求服务id
            /// </summary>
            public byte sid;

            /// <summary>
            /// 错误码
            /// </summary>
            public byte error_code;
        }


        /// <summary>
        /// 帧
        /// </summary>
        [StructLayoutAttribute(LayoutKind.Sequential, Pack = 4)]
        public struct ZUDS_FRAME
        {
            /// <summary>
            /// 帧id
            /// </summary>
            public UInt32 id;

            /// <summary>
            /// 1:扩展帧 0:标准帧
            /// </summary>
            public Byte extend;

            /// <summary>
            ///  1:远程帧 0:数据帧
            /// </summary>
            public Byte remote;

            /// <summary>
            /// 数据长度
            /// </summary>
            public Byte data_len;

            /// <summary>
            /// 数据数组
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public Byte[] data;

            public UInt32 reserved; // 保留
        }

        /// <summary>
        /// 会话层设置参数
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct ZUDS_SERSSION_PARAM
        {
            /// <summary>
            /// 响应超时时间, 单位毫秒
            /// </summary>
            public UInt16 timeout; // 

            /// <summary>
            /// 收到消极响应错误码为0x78后的超时时间
            /// </summary>
            public UInt16 enhanced_timeout;

            public UInt32 reserved0; // 保留
            public UInt32 reserved1; // 保留
        }

        // 传输层设置参数
        [StructLayout(LayoutKind.Sequential)]
        public struct ZUDS_ISO15765_PARAM
        {
            /// <summary>
            /// 传输协议版本, VERSION_0, VERSION_1
            /// </summary>
            public byte version;

            /// <summary>
            /// 单帧最大数据长度, can:8, canfd:64
            /// </summary>
            public byte max_data_len;

            /// <summary>
            /// 本程序发送流控时用，连续帧之间的最小间隔, 0x00-0x7F(0ms~127ms), 0xF1-0xF9(100us~900us)
            /// </summary>
            public byte st_min;

            /// <summary>
            /// 流控帧的块大小
            /// </summary>
            public byte block_size;

            /// <summary>
            /// 无效字节的填充数据
            /// </summary>
            public byte fill_byte;

            /// <summary>
            ///  0:标准帧 1:扩展帧
            /// </summary>
            public byte frame_type;

            /// <summary>
            /// 是否忽略ECU返回流控的STmin，强制使用本程序设置的 remote_st_min
            /// </summary>
            public byte is_modify_ecu_st_min;

            /// <summary>
            /// 发送多帧时用, is_ignore_ecu_st_min = 1 时有效, 0x00-0x7F(0ms~127ms), 0xF1-0xF9(100us~900us)
            /// </summary>
            public byte remote_st_min;

            public UInt16 reserved; // 保留
        }

        /// <summary>
        /// 会话保持的设置参数
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct ZUDS_TESTER_PRESENT_PARAM
        {
            /// <summary>
            /// 请求地址
            /// </summary>
            public UInt32 addr;

            /// <summary>
            /// 发送周期, 单位毫秒
            /// </summary>
            public UInt16 cycle;

            /// <summary>
            /// 1:抑制响应
            /// </summary>
            public byte suppress_response;

            public UInt32 reserved; // 保留
        }
        #endregion


        #region 库函数

        /// <summary>
        /// 初始化资源, 获取操作句柄
        /// </summary>
        /// <param name="type">目前只支持DoCAN</param>
        /// <returns>操作句柄, 供之后的函数使用; 初始化失败返回ZUDS_INVALID_HANDLE</returns>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern ZUDS_HANDLE ZUDS_Init(TP_TYPE type);

        /// <summary>
        /// 执行服务请求, 阻塞函数, ECU有响应或响应超时返回
        /// </summary>
        /// <param name="handle">ZUDS_Init的返回值</param>
        /// <param name="request">请求结构体, 详见ZUDS_REQUEST</param>
        /// <param name="response">响应结构体, 详见ZUDS_RESPONSE</param>
        /// <returns></returns>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_Request(ZUDS_HANDLE handle, ref ZUDS_REQUEST request, ref ZUDS_RESPONSE response);

        /// <summary>
        /// 中止请求, ZUDS_Request返回
        /// </summary>
        /// <param name="handle"></param>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_Stop(ZUDS_HANDLE handle);

        /// <summary>
        /// 发送帧数据回调函数
        /// </summary>
        /// <param name="ctx">通过ZUDS_SetTransmitHandler传入的参数, 回调函数中传出</param>
        /// <param name="frame">帧数组</param>
        /// <param name="count">帧数组元素个数</param>
        /// <returns></returns>
        [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public delegate UInt32 OnUDSTransmit(IntPtr ctx, ZUDS_FRAME[] zudsFrame, UInt32 count);

        /// <summary>
        /// 设置发送回调函数
        /// </summary>
        /// <param name="handle">ZUDS_Init的返回值</param>
        /// <param name="ctx">上下文参数, 在回调函数中传出, 库内部不会处理该参数</param>
        /// <param name="transmittor">回调函数, 一定要实现, 不然无法实现报文交互</param>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_SetTransmitHandler(ZUDS_HANDLE handle, IntPtr ctx, Delegate transmittor);

        /// <summary>
        /// 库外部接收到的帧数据通过该函数传入, 一定要调用, 不然无法实现报文交互
        /// </summary>
        /// <param name="handle">ZUDS_Init的返回值</param>
        /// <param name="frame"></param>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_OnReceive(ZUDS_HANDLE handle, ref ZUDS_FRAME framePtr);

        /// <summary>
        /// 设置参数
        /// </summary>
        /// <param name="handle">ZUDS_Init的返回值</param>
        /// <param name="type">type=PARAM_TYPE_SESSION, param:详见ZUDS_SESSION_PARAM传输层参数, 
        ///                                        type=PARAM_TYPE_ISO15765, param:详见ZUDS_ISO15765_PARAM</param>
        /// <param name="param"></param>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_SetParam(ZUDS_HANDLE handle, PARAM_TYPE type, IntPtr param);

        /// <summary>
        /// 用于实现会话保持false
        /// </summary>
        /// <param name="handle">ZUDS_Init的返回值</param>
        /// <param name="enable">enable: true=使能会话保持, false=禁能会话保持</param>
        /// <param name="param"></param>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_SetTesterPresent(ZUDS_HANDLE handle, byte enable, IntPtr paramPtr);

        /// <summary>
        /// 启动独立的流控响应。当接收到响应地址的多帧数据时，按请求地址回应流控数据
        /// 由于ZUDS_Request请求过程中也会回应流控帧，本功能可能被ZUDS_Request修改响应地址而影响，所以不建议与请求同时使用。请单独申请个ZUDS_HANDLE做独立的流控响应。
        ///如果使用两个ZUDS_HANDLE，为了避免发送两次相同的流控响应，请使用ZUDS_Request前关闭本功能。
        /// </summary>
        /// <param name="handle">ZUDS_Init的返回值</param>
        /// <param name="src_addr">请求地址</param>
        /// <param name="dst_addr">响应地址, ECU的地址</param>
        /// <returns></returns>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern UDS_STATUS ZUDS_StartAloneFlowControl(ZUDS_HANDLE handle, UInt32 src_addr, UInt32 dst_addr);

        /// <summary>
        /// 停止独立的流控响应
        /// </summary>
        /// <param name="handle"></param>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_StopAloneFlowControl(ZUDS_HANDLE handle);

        /// <summary>
        /// 释放资源, 与ZUDS_Init配对使用
        /// </summary>
        /// <param name="handle"></param>
        [DllImport("zuds.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void ZUDS_Release(ZUDS_HANDLE handle);

        #endregion


        /// <summary>
        /// 将CAN FRAME转换为UDS FRAME
        /// </summary>
        /// <param name="uds">ZUDS_FRAME</param>
        /// <param name="can">ZCAN_Receive_Data</param>
        public static void ZCANToUDSFrame(ref ZUDS_FRAME uds, uint can_id, byte can_dlc, byte[] bData)
        {
            uds = new ZUDS_FRAME();
            if (bData != null)
            {
                uds.id = can_id;
                uds.extend = (byte)(Method.IsEFF(can_id) == true ? 1 : 0);
                uds.remote = (byte)(Method.IsRTR(can_id) == true ? 1 : 0);
                uds.data_len = can_dlc;
                uds.data = new byte[64];
                Array.Copy(bData, 0, uds.data, 0, uds.data_len);
            }
        }

        /// <summary>
        /// ZUDS_FRAME转ZCAN_Transmit_Data
        /// </summary>
        /// <param name="zlgcan">ZCAN_Transmit_Data</param>
        /// <param name="uds">ZUDS_FRAME</param>
        /// <param name="count">发送数量</param>
        public static void UDSFrameToZCAN(ref ZCAN_Transmit_Data[] zlgcan, ref CAN_OBJ[] gccan, ZUDS_FRAME[] uds, UInt32 count)
        {
            for (UInt32 i = 0; i < count; ++i)
            {
                gccan[i].ID = zlgcan[i].frame.can_id = Method.MakeCanId(uds[i].id, uds[i].extend, uds[i].remote, 0);
                gccan[i].DataLen = zlgcan[i].frame.can_dlc = uds[i].data_len;
                gccan[i].data = zlgcan[i].frame.data = new byte[uds[i].data_len];

                Array.Copy(uds[i].data, gccan[i].data, uds[i].data_len);
                Array.Copy(uds[i].data, zlgcan[i].frame.data, uds[i].data_len);
            }
        }

        /// <summary>
        /// 回调函数进行发送
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="frame">ZUDS_FRAME</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public static UInt32 OnUDSTransmitFunc(IntPtr ctx, ZUDS_FRAME[] frame, UInt32 count)
        {
            IntPtr ctxPtr = ctx;
            ZCAN_Transmit_Data[] can_data = new ZCAN_Transmit_Data[count];
            CAN_OBJ[] gccan = new CAN_OBJ[count];

            UInt32 iTxStatus;
            //if (frame[0].data[0] == 0x10 && frame[0].data[2] == 0x31)
            //{
            //    frame[0].data[3] = 0x01;
            //    frame[0].data[4] = 0xFB;
            //    frame[0].data[5] = 0x35;
            //    frame[0].data[6] = 0xAA;
            //    frame[0].data[7] = 0x55;
            //}
            string strData = string.Format("传入    :DATA[{0}]", Change.BytesToHexString(frame[0].data, 0, frame[0].data_len, " "));
            tLog.WriteLog(strData, "data");
            UDSFrameToZCAN(ref can_data, ref gccan, frame, count);


            IntPtr ptr = Marshal.AllocHGlobal((IntPtr)(Marshal.SizeOf(typeof(ZCAN_Transmit_Data)) * count));
            for (int i = 0; i < count; i++)
            {
                Marshal.StructureToPtr(can_data[i], ptr, false);
                strData = string.Format("发送    :ID[0x{0:X6}], DATA[{1}]", can_data[i].frame.can_id, Change.BytesToHexString(can_data[i].frame.data, 0, can_data[i].frame.can_dlc, " "));
                tLog.WriteLog(strData, "data");
            }
            try
            {
                if (CanCommunication.bZlgCan)
                {
                    iTxStatus = count == Method.ZCAN_Transmit(Method.channel_handle[(int)ctx], ptr, count) ? TRANSPORT_OK : TRANSPORT_ERROR;
                }
                else
                {
                    iTxStatus = count == ECANDLL.GcSendCanObj((int)ctx, gccan, count) ? TRANSPORT_OK : TRANSPORT_ERROR;
                }

                return iTxStatus;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return 3;
            }
        }

        /// <summary>
        /// 设置参数
        /// </summary>
        public static void Setparam(int iPassageway)
        {
            ZUDS_ISO15765_PARAM tp = new ZUDS_ISO15765_PARAM();
            tp.block_size = 0;
            tp.fill_byte = 0x00;
            tp.st_min = 0;
            tp.is_modify_ecu_st_min = 0;
            tp.remote_st_min = 0;
            tp.frame_type = 0;
            tp.version = VERSION_0;
            tp.max_data_len = (byte)(0 == tp.version ? 8 : 64); // 帧数据最长长度
            use_canfd = tp.max_data_len > 8;

            IntPtr ptr = Change.structToIntptr(tp);

            ZUDS_SetParam(zudsHandle[iPassageway], PARAM_TYPE_ISO15765, ptr);
            Marshal.FreeHGlobal(ptr);

            ZUDS_SERSSION_PARAM sparam = new ZUDS_SERSSION_PARAM();
            sparam.enhanced_timeout = 2000;
            sparam.timeout = 5000;
            ptr = Change.structToIntptr(sparam);
            ZUDS_SetParam(zudsHandle[iPassageway], PARAM_TYPE_SESSION, ptr);
            Marshal.FreeHGlobal(ptr);
        }

        public static bool[] isReqRecv = new bool[9];
        /// <summary>
        /// 执行服务函数
        /// </summary>
        /// <param name="iPassageway">通道号</param>
        /// <param name="strSrcID">发送ID</param>
        /// <param name="strDstID">接收ID</param>
        /// <param name="bTxComm">发送数据</param>
        /// <returns></returns>
        public static ZUDS_RESPONSE GetRequest(int iPassageway, string strSrcID, string strDstID, byte[] bTxComm, ref byte[] bRecvData, bool bLenth)
        {
            byte[] bReqData;
            int iCount;
            ZUDS_RESPONSE resp = new ZUDS_RESPONSE();

            if (bTxComm[0] == 0xAA && bTxComm[1] == 0x55)
            {
                bReqData = new byte[bTxComm.Length + 4];
                bReqData[0] = 0x31;
                bReqData[1] = 0x01;
                bReqData[2] = 0xFB;
                bReqData[3] = 0x35;
                Array.Copy(bTxComm, 0, bReqData, 4, bTxComm.Length);
            }
            else
            {
                if (bLenth == true)
                {
                    bReqData = new byte[bTxComm[0]];
                    Array.Copy(bTxComm, 1, bReqData, 0, bTxComm[0]);
                }
                else
                {
                    UInt32 iRet = 0;
                    bReqData = new byte[8];
                    Array.Copy(bTxComm, 0, bReqData, 0, 8);
                    ZCAN_Transmit_Data can_data = new ZCAN_Transmit_Data();
                    can_data.frame.can_id = Convert.ToUInt32(strSrcID, 16);
                    can_data.frame.can_dlc = 8;
                    can_data.frame.data = bReqData;
                    if (Method.nDeviceType[iPassageway] != 88)
                    {
                        iRet = Method.SendData(iPassageway, can_data);
                    }
                    else
                    {
                        iRet = ECANDLL.GcSendData(iPassageway, Change.BytesToHexString(bReqData, 0, 8, " "), strSrcID);
                    }

                    string str = "发送 ";
                    str += iRet.ToString() + "  帧ID:" + strSrcID;
                    str += "  数据:" + Change.BytesToHexString(bReqData, 0, bReqData.Length, " ");
                    tLog.WriteLog(str, "data");

                    isReqRecv[iPassageway] = false;
                    return resp;
                }
            }
            string strData = string.Format("组帧    :DATA[{0}]", Change.BytesToHexString(bReqData, 0, bReqData.Length, " "));
            tLog.WriteLog(strData, "data");

            //Setparam(iPassageway);

            ZUDS_REQUEST req = new ZUDS_REQUEST
            {
                src_addr = Convert.ToUInt32(strSrcID, 16),
                dst_addr = Convert.ToUInt32(strDstID, 16),
                suppress_response = 0,
                sid = bReqData[0],                                                      // 服务ID
                param_len = (uint)(bReqData.Length - 1)
            };
            byte[] bData = new byte[req.param_len];
            Array.Copy(bReqData, 1, bData, 0, req.param_len);
            req.param = IntPtr.Zero;
            req.param = Change.BytesToIntptr(bData);

            
            Setparam(iPassageway);
            startSessionKeep(iPassageway);
            try
            {
                iCount = 0;
                while (iCount < 1)
                {
                    ZUDS_Request(zudsHandle[iPassageway], ref req, ref resp);
                    string strTemp = "";
                    if (resp.status == ZUDS_ERROR_OK)
                    {
                        if (resp.type == RT_POSITIVE)
                        {
                            int iLen = (int)resp.un.positive.param_len;

                            byte[] bTemp = new byte[iLen];
                            Marshal.Copy(resp.un.positive.param, bTemp, 0, iLen);
                            strTemp = string.Format("积极响应：状态[{0}]; ID[0x:{1:X8}]; DATA[{2}]", resp.status, resp.un.positive.sid, Change.BytesToHexString(bTemp, 0, iLen, ""));

                            if (bTxComm[0] == 0xAA && bTxComm[1] == 0x55)
                            {
                                bRecvData = new byte[iLen - 3];
                                Array.Copy(bTemp, 3, bRecvData, 0, iLen - 3);
                            }
                            else
                            {
                                bRecvData = bTemp;
                            }
                            break;
                        }
                        else
                        {
                            strTemp = string.Format("消极响应：状态[{0}]; DATA[{1:X2}{2:X2}{3:X2}]", resp.status, resp.un.negative.neg_code, resp.un.negative.sid, resp.un.negative.error_code);
                        }
                        Console.WriteLine(strTemp);
                    }
                    iCount++;
                    Thread.Sleep(5);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            return resp;
        }

        /// <summary>
        /// 是否保持会话连接
        /// </summary>
        static bool session_keep_enable_ = false;

        /// <summary>
        /// 是否已保持
        /// </summary>
        static bool session_keep_running_ = false;

        /// <summary>
        /// 会话保持发送周期
        /// </summary>
        static UInt16 session_keep_period_ = 2000;

        /// <summary>
        /// 保持会话连接
        /// </summary>
        /// <param name="iChannel"></param>
        public static void startSessionKeep(int iChannel)
        {
            IntPtr nullptr = new IntPtr();

            if (session_keep_enable_)
            {
                if (session_keep_running_)
                {
                    ZUDS_SetTesterPresent(zudsHandle[iChannel], 0, nullptr);
                }
                ZUDS_TESTER_PRESENT_PARAM param = new ZUDS_TESTER_PRESENT_PARAM();
                param.addr = Convert.ToUInt32(1 == 1 ? "7DF" : "723", 16);
                param.cycle = session_keep_period_;
                param.suppress_response = 1;

                nullptr = Change.structToIntptr(param);
                ZUDS_SetTesterPresent(zudsHandle[iChannel], 1, nullptr);
                session_keep_running_ = true;
            }
            else
            {
                if (session_keep_running_)
                {

                    ZUDS_SetTesterPresent(zudsHandle[iChannel], 0, nullptr);
                }
                session_keep_running_ = false;
            }
        }

        public static Random rd = new Random();
        //        public static int Volvo_27(ref ZUDS_REQUEST req, ref ZUDS_RESPONSE rsp)
        //        {



        //    //1.Create client_random_number
        //            byte[] client_random_number = new byte[16];
        //    for (int i = 0; i< 16; i++)
        //    {
        //        client_random_number[i] = (byte)rd.Next(1, 0xFF);
        //    }
        //    Console.WriteLine("client_random_number:");
        //            Console.WriteLine(Change.BytesToHexString(client_random_number, 0, 16, " "));

        //    //2.Create random IV
        //    byte[] iv = new byte[16];
        //            for (int i = 0; i < 16; i++)
        //            {
        //                iv[i] = (byte)rd.Next(1, 0xFF);
        //            }
        //            Console.WriteLine("iv:");
        //            Console.WriteLine(Change.BytesToHexString(iv, 0, 16, " "));

        //            //3.Encrypt client_random_number: AES-CTR-ENC(IV, client_random_number)
        //            byte[] client_encrypted_data_record = new byte[16];
        //am_aes_ctr_enc(ENC_AUTH_KEY_ID, iv, client_random_number, client_encrypted_data_record, 16);
        //UP_INFO("encrypted_data_record:");
        //UP_INFO_HEX(client_encrypted_data_record, 16);

        ////4.Construct struct for authentication data generation: sid, subid, message_id, authentication_method, iv, encrypted_data_record(step3)
        //uint8_t req_seed_msg[54] = { 0x27, 0x01, 0x00, 0x01, 0x00, 0x01 };
        //memcpy(&req_seed_msg[6], iv, 16);
        //memcpy(&req_seed_msg[6 + 16], client_encrypted_data_record, 16);

        ////5.Generate authentication_data: AES-CMAC(clientRequestSeed)
        //uint8_t authentication_data[16];
        //am_cmac_generate(ENC_AUTH_KEY_ID, authentication_data, req_seed_msg, 38);
        //memcpy(&req_seed_msg[6 + 16 + 16], authentication_data, 16);
        //UP_INFO("req_seed_msg:");
        //UP_INFO_HEX(req_seed_msg, 54);

        ////6.send request message and wait receive response
        //req->sid = 0x27;
        //req->src_addr = UDS_PHY_ID;
        //memcpy(req->param, &req_seed_msg[1], 53);
        //req->param_len = 53;
        //if (ODX_COMM_OK != odx_comm(req, rsp, 500))
        //{
        //    UP_ERROR("27 01 failed, exit\n");
        //    return -1;//exit(1);
        //}
        //if (rsp->positive.param_len != 67)
        //{
        //    UP_ERROR("67 01应答数据长度错误\n");
        //    return -1; //exit(1);
        //}

        //UP_INFO("RCV 2701 RSP(%d):\n", rsp->positive.param_len);
        //UP_INFO_HEX(rsp->positive.param, rsp->positive.param_len);

        ////16.Verify serverResponseSeed message authentication_data
        //rsp_6701.security_access_response_sid = 0x67;
        //memcpy(((uint8_t*)&rsp_6701 + 1), rsp->positive.param, rsp->positive.param_len);
        //UP_INFO_HEX((uint8_t*)&rsp_6701 + 1, 67);

        //int ret = am_cmac_verify(OWNERSHIP_KEY_ID, rsp_6701.authentication_data, (uint8_t*)&rsp_6701, rsp->positive.param_len - 15);
        //if (ret != 0)
        //{
        //    UP_INFO_HEX(rsp_6701.authentication_data, 16);
        //    UP_ERROR("6701 check authentication data failed.exit\n");
        //    return -1;//exit(0);
        //}
        //else
        //{
        //    UP_INFO("6701 check authentication data success!\n");
        //}

        ////17.Decrypt encrypted_data_record to get: server_random_number, server_proof_of_ownership
        //uint8_t server_random_number[16]; //从接收数据中解密出来
        //uint8_t server_proof_of_ownership[16] = { 0x0 }; //AES-128-CMAC from server_random_number and client_random_number
        //uint8_t tmp_17[32];
        //am_aes_ctr_dec(ENC_AUTH_KEY_ID, rsp_6701.iv, rsp_6701.encrypted_data_record, tmp_17, 32); //解密出server_random_number
        //memcpy(server_random_number, tmp_17, 16);
        //memcpy(server_proof_of_ownership, &tmp_17[16], 16);
        //UP_INFO("server_random_number:\n");
        //UP_INFO_HEX(server_random_number, 16);
        //UP_INFO("server_proof_of_ownership:\n");
        //UP_INFO_HEX(server_proof_of_ownership, 16);

        //uint8_t param_random[32];
        //memcpy(param_random, server_random_number, 16);
        //memcpy(&param_random[16], client_random_number, 16);
        //am_cmac_generate(OWNERSHIP_KEY_ID, server_proof_of_ownership, param_random, 32); //get server_proof_of_ownership

        ////18.Verify server_proof_of_ownership
        //ret = am_cmac_verify(OWNERSHIP_KEY_ID, server_proof_of_ownership, param_random, 32);
        //if (ret != 0)
        //{
        //    UP_ERROR("6701: Verify server_proof_of_ownership failed, exit\n");
        //    return -1;//exit(0);
        //}

        ////19.Create random IV
        //uint8_t iv_2702[16];
        //for (int i = 0; i < 16; i++)
        //{
        //    iv_2702[i] = rand() % 0xFF;
        //}
        //UP_INFO("iv_2702:");
        //UP_INFO_HEX(iv_2702, 16);

        ////20.Create client_proof_of_ownership: AES-CMAC(client_random_number, server_random_number)
        //uint8_t client_proof_of_ownership[16];
        //memcpy(param_random, client_random_number, 16);
        //memcpy(&param_random[16], server_random_number, 16);
        //am_cmac_generate(OWNERSHIP_KEY_ID, client_proof_of_ownership, param_random, 32);
        ////am_cmac_generate(OWNERSHIP_KEY_ID, client_proof_of_ownership, param_random, 32);


        ////21.Encrypt client_proof_of_ownership: AES-CTR-ENC(iv, client_proof_of_ownership)
        //uint8_t encrypted_data_record_2702[16];
        //am_aes_ctr_enc(OWNERSHIP_KEY_ID, iv_2702, client_proof_of_ownership, encrypted_data_record_2702, 16);

        ////22. Construct stucture for authentication data generation: rsp_sid, subid, message_id, iv, encrypted_data_record(step21)
        //uint8_t req_key_msg[52] = { 0x27, 0x02, 0x00, 0x03 };
        //memcpy(&req_key_msg[4], iv_2702, 16);
        //memcpy(&req_key_msg[4 + 16], encrypted_data_record_2702, 16);


        ////23.Generate authentication_data for clientSeedKey message: AES-CMAC(clientSeedKey)
        //uint8_t req_2702_auth[16];
        //am_cmac_generate(ENC_AUTH_KEY_ID, &req_key_msg[36], req_key_msg, 36);

        ////24. send clientSeedKey and wait serverResponseKey response message
        //req->sid = 0x27;
        //req->src_addr = UDS_PHY_ID;
        //memcpy(req->param, &req_key_msg[1], 51);
        //req->param_len = 51;
        //if (ODX_COMM_OK != odx_comm(req, rsp, 500))
        //{
        //    UP_ERROR("27 02 comm failed, exit\n");
        //    //exit(1);
        //    return -1;
        //}
        //UP_INFO("RCV 2702 RSP(%d):\n", rsp->positive.param_len);
        //UP_INFO_HEX(rsp->positive.param, rsp->positive.param_len);
        //return 0;
        //        }
    }
}
